﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;

namespace QuantitativeIndicator.Hurst
{
    //此模块只考虑计算的正确性，至于点够不够，日期是否合适这些问题，则放在输出环节去控制
    class HurstCaculatorRS
    {
        public HurstDataModel db;
        
        public HurstCaculatorRS()
        {
            this.db=new HurstDataModel();
        }
        //计算RS序列
        public double[,] CaculateRS(int noOfCalPoints, string indexTradingCode, string calDate)
        {
            double[] logRtnIdx=db.getIndexRtnSeries(noOfCalPoints,indexTradingCode,calDate,"log");//收益序列
            double[,] rs=null; //rs[0,]代表子区间的长度，rs[1,]代表RS值

                rs = new double[2, logRtnIdx.Length - 2];//定义RS序列
                for (int N = 3; N <= logRtnIdx.Length; N++) //N代表子区间的长度
                {
                    //Console.WriteLine(N);
                    double[] tmpArr1 = new double[N];//记录均值和方差
                    double[] tmpArr2 = new double[N];//记录累计偏离均值
                    int noOfN = logRtnIdx.Length - N + 1;
                    double avgRange = 0;
                    double avgStdev = 0;
                    double totalRange = 0;//总极差
                    double totalStdev = 0;//总标准差

                    for (int nCounter = 1; nCounter <= noOfN; nCounter++)
                    {
                        //进行分组计算
                        for (int i = 1; i <= N; i++)
                        {
                            tmpArr1[i - 1] = logRtnIdx[nCounter - 2 + i];
                            tmpArr2[i - 1] = 0;
                        }
                        double sumIdxRtn=0;//记录收益之和，为了计算meanIdxRtn
                        double meanIdxRtn = 0;//记录收益均值
                        double sumSquaIdxRtn = 0;//记录收益平方和
                        double stdevIdxRtn = 0;//记录收益标准差
                        double maxSumMeanDev = 0, minSumMeanDev = 0;//记录累计偏离均值的最大值和最小值

                        for (int i = 1; i <= N; i++)
                        {
                            sumIdxRtn+=tmpArr1[i-1];
                            sumSquaIdxRtn += tmpArr1[i - 1] * tmpArr1[i - 1];
                        }
                        meanIdxRtn = sumIdxRtn / N;
                        stdevIdxRtn = Math.Sqrt((sumSquaIdxRtn-(sumIdxRtn*sumIdxRtn/N))/N);
                        totalStdev += stdevIdxRtn;//计算总标准差
                        
                        //计算极差
                        for (int i = 1; i <= N; i++)
                        {
                            tmpArr1[i - 1] = tmpArr1[i - 1] - meanIdxRtn;
                            for (int j = 1; j <= i; j++)
                            {
                                tmpArr2[i-1] += tmpArr1[j - 1];
                            }
                            //判断累计均值偏差的最大值和最小值
                            if (tmpArr2[i - 1] > maxSumMeanDev)
                            {
                                maxSumMeanDev = tmpArr2[i - 1];
                            }
                            if (tmpArr2[i - 1] < minSumMeanDev)
                            {
                                minSumMeanDev = tmpArr2[i - 1];
                            }
                        }
                        totalRange += maxSumMeanDev - minSumMeanDev;//计算总极差
                    }
                    avgRange = totalRange / noOfN;
                    avgStdev = totalStdev / noOfN;
                    rs[0, N - 3] = N;
                    rs[1, N - 3] = avgRange / avgStdev;
                }
            return rs;
        }
        //计算V统计量
        public double[] CaculateVStat(double[,] RSList)
        {
            int m = RSList.GetLength(1);
            double[] tmpV=new double[m];

            for (int i = 0; i < m; i++)
            {
                tmpV[i] = RSList[1, i] / (Math.Sqrt(RSList[0, i]));
            }

                return tmpV;
        }
        //计算单个Hurst指数
        public double CaculateHurst(int noOfCalPoints, string indexTradingCode, string calDate)
        {
            double expH = 0;
            double[,] tmpRS = CaculateRS(noOfCalPoints, indexTradingCode, calDate);
            //回归的问题可以有专门的模块解决，待更新！！
            double M = tmpRS.GetLength(1);
            double sumX = 0;
            double sumY = 0;
            double sumXY = 0;
            double sumXX = 0;

            for (int i = 0; i < M; i++)
            {
                tmpRS[0, i] = Math.Log10(tmpRS[0, i]);//X
                tmpRS[1, i] = Math.Log10(tmpRS[1, i]);//Y
                sumX += tmpRS[0, i];
                sumY += tmpRS[1, i];
                sumXY += tmpRS[0, i] * tmpRS[1, i];
                sumXX += tmpRS[0, i] * tmpRS[0, i];
            }
            expH = (sumXY - (sumX * sumY / M)) / (sumXX - (sumX * sumX) / M);
            return expH;
        }
        //计算Hurst指数序列，有bug!!!
        public double[] CaculateHurstSeries(int noOfCalPoints, string indexTradingCode,string startDate, string endDate)
        {
            double[] expHSeries;
            List<string> dateList = new List<string>();
            dateList = db.getTradingDate(startDate, endDate);
            expHSeries = new double[dateList.Count];
            int i = 0;
            foreach (string element in dateList)
            {
                expHSeries[i] = CaculateHurst(noOfCalPoints, indexTradingCode, element);
                i++;
            }
            return expHSeries;
        }
    }
}
